﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace per.esmool.utils {

    public static class JsonKit {

        public static string ToJson(object obj) {
            var builder = new StringBuilder();
            using var writer = new StringWriter(builder);
            var serializer = new JsonSerializer();
            serializer.Serialize(writer, obj);
            return builder.ToString();
        }

        public static T GetValue<T>(JObject json, string key, T defaultValue) {
            if (json is null)
                return defaultValue;
            if (!json.ContainsKey(key))
                return defaultValue;
            return json.Value<T>(key);
        }

        public static T ParseValue<T>(JObject json, string key, Func<string, T> parser, T defaultValue) {
            if (json is null)
                return defaultValue;
            if (!json.ContainsKey(key))
                return defaultValue;
            var text = json.Value<string>(key);
            var value = parser.Invoke(text);
            return value;
        }

        public static T GetValue<T>(JArray array, int index, T defaultValue) {
            if (array is null)
                return defaultValue;
            if (index < 0 || index >= array.Count)
                return defaultValue;
            return array.Value<T>(index);
        }

        public static T ParseValue<T>(JArray array, int index, Func<string, T> parser, T defaultValue) {
            if (array is null)
                return defaultValue;
            if (index < 0 || index >= array.Count)
                return defaultValue;
            var text = array.Value<string>(index);
            var value = parser.Invoke(text);
            return value;
        }

        public static Dictionary<string, JObject> GetBaseItems(JArray array, string keyField = "name") {
            Dictionary<string, JObject> baseItems = [];
            foreach (var item in array) {
                if (item is not JObject json)
                    continue;
                if (!json.ContainsKey(keyField))
                    continue;
                var name = json.Value<string>(keyField);
                var isBase = GetValue(json, "BaseConfig", false);
                if (!isBase)
                    continue;
                baseItems.Add(name, json);
            }
            return baseItems;
        }

        public static JArray Merge(JArray array, string keyField = "name", JsonMergeSettings settings = null) {
            var baseItems = GetBaseItems(array, keyField);
            var result = new JArray();
            foreach (var item in array) {
                if (item is not JObject json)
                    continue;
                var isBase = GetValue(json, "BaseConfig", false);
                if (isBase)
                    continue;
                var refName = GetValue<string>(json, "ref", null);
                if (refName is null) {
                    result.Add(item);
                    continue;
                }
                var refItem = baseItems[refName];
                var merged = new JObject();
                merged.Merge(refItem, settings);
                merged.Merge(item);
                merged.Remove("BaseConfig");
                merged.Remove("ref");
                result.Add(merged);
            }
            return result;
        }

        internal static JArray Merge(JArray data, object value, JsonMergeSettings jsonMergeSettings) {
            throw new NotImplementedException();
        }
    }
}
